﻿using System;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Serialization;
using System.Data;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Text;

namespace GlobalCalendarWebPart
{
    [Guid("80de2eac-13ad-423d-970f-834683d809d4")]
    public class GlobalCalendarWebPart : System.Web.UI.WebControls.WebParts.WebPart
    {
        public GlobalCalendarWebPart()
        {
        }

        private string _sitesExclosos = "";
        [Personalizable(PersonalizationScope.User), WebBrowsable, WebDisplayName("Sites Exclosos: ex.(site1,site2,site3,..)"), WebDescription("Sites exclosos de la web part, dels quals no volem recuperar els items dels calendaris. ex.(site1,site2,site3)")]
        public string SitesExclosos
        {
            get { return _sitesExclosos; }
            set { _sitesExclosos = value; }
        }

        private SPUser UsuarioActual = null;

        /// <summary>
        /// Called by the ASP.NET page framework to notify server controls 
        /// that use composition-based implementation to create any child 
        /// controls they contain in preparation for posting back or 
        /// rendering.
        /// </summary>

        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            try
            {
                SPWeb webActual = SPContext.Current.Web;
                webActual.Site.CatchAccessDeniedException = false;
                UsuarioActual = webActual.CurrentUser;
                // run as system administrator
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    AddCalendar();
                });
            }
            catch (Exception ex)
            {
                Controls.Add(new LiteralControl("<b>Error</b> "));
                Controls.Add(new LiteralControl(ex.ToString()));
            }
            
        }

        /// <summary>
        /// Adds the calendar to web part.
        /// </summary>

        private void AddCalendar()
        {
            SPSite site = new SPSite(SPContext.Current.Web.Url);
            SPWebCollection webCol = site.AllWebs;

            DataTable results;
            SPCalendarView calView = new SPCalendarView();
            calView.ViewType = GetCalendarType(Page.Request["CalendarPeriod"]);
            SPCalendarItemCollection TodosItems = new SPCalendarItemCollection();
            char[] c = { ',' };
            string[] SitesExc = _sitesExclosos.Split(c);

            foreach (SPWeb web in webCol)
            {
                if ((EsUsuarioConPermisos(web)) && (!EstaAquestSiteExclos(web, SitesExc)))
                {
                    results = GetQueryData(web);
                    GetCalendarItems(web, results, ref TodosItems);
                }
            }
            calView.DataSource = TodosItems;
            calView.DataBind();
            Controls.Add(calView);
        }

        /// <summary>
        /// Executes the query against the web and returns 
        /// results as DataTable.
        /// </summary>
        /// <param name="web">The web that is queried.</param>
        /// <returns>Query results as DataTable.</returns>

        private DataTable GetQueryData(SPWeb web)
        {
            SPListCollection listas = web.Lists;
            SPSiteDataQuery query = new SPSiteDataQuery();

            StringBuilder listaQuery = new StringBuilder();
            listaQuery.Append(@"<Lists>");
            foreach (SPList l in web.Lists)
            {
                listaQuery.Append("<List ID='{" + l.ID + "}' />");
            }
            listaQuery.Append("</Lists>");

            query.Lists = listaQuery.ToString();

            query.Query = @"<Where>
                        <Gt>
                            <FieldRef Name='ID' />
                            <Value Type='Number'>0</Value>
                        </Gt>
                    </Where>";
            query.Webs = "<Webs Scope='SiteCollection' />";
            query.ViewFields = "<FieldRef Name='Title' />";
            query.ViewFields += "<FieldRef Name='ID' />";
            query.ViewFields += "<FieldRef Name='EventDate' />";
            query.ViewFields += "<FieldRef Name='EndDate' />";
            query.ViewFields += "<FieldRef Name='Location' />";
            query.ViewFields += "<FieldRef Name='Description' />";
            query.ViewFields += "<FieldRef Name='fRecurrence' />";
            query.RowLimit = 100;
            return web.GetSiteData(query);
        }

        /// <summary> 
        /// Gets the collection of calendar items based on site 
        /// data query results.
        /// </summary>
        /// <param name="web">The web that was queried.</param>
        /// <param name="results">The results of query.</param>
        /// <returns>Collection of calendar items accepted by 
        /// calendar component</returns>

        private void GetCalendarItems(SPWeb web, DataTable results, ref SPCalendarItemCollection items)
        {
            //SPCalendarItemCollection items = new SPCalendarItemCollection();
          
            foreach (DataRow row in results.Rows)
            {
                Guid listGuid = new Guid(row["ListId"] as string);
                SPList list = web.Lists[listGuid];

                SPCalendarItem item = new SPCalendarItem();

                foreach (SPForm form in list.Forms)
                {
                    if (form.Type == PAGETYPE.PAGE_DISPLAYFORM)
                    {
                        item.DisplayFormUrl = form.ServerRelativeUrl;
                        break;
                    }
                }

                string recurrence = (row["fRecurrence"].ToString().Length == 0)? "0" :row["fRecurrence"].ToString();
                string AllDayEvent = (row["fAllDayEvent"].ToString().Length == 0) ? "0" : row["fAllDayEvent"].ToString();
                item.ItemID = row["ID"] as string;
                item.StartDate = DateTime.Parse(row["EventDate"] as string);
                item.EndDate = DateTime.Parse(row["EndDate"] as string);
                item.hasEndDate = true;
                item.Title = row["Title"] as string;
                item.Location = row["Location"] as string;
                item.Description = row["Description"] as string;
                item.IsAllDayEvent = (int.Parse(AllDayEvent) != 0);
                item.IsRecurrence = (int.Parse(recurrence) != 0);
                item.CalendarType = Convert.ToInt32(SPCalendarType.Gregorian);
                items.Add(item);
            }
            //return items;

        }

        /// <summary>
        /// Gets the type of the calendar view.
        /// </summary>
        /// <param name="type">The type to be checked.</param>
        /// <returns>Correct view type of calendar.</returns>

        private static string GetCalendarType(string type)
        {
            if (type == null)
            {
                type = string.Empty;
            }
            switch (type.ToLower())
            {
                case "day": return "day";
                case "week": return "week";
                case "timeline": return "timeline";
                default: return "month";
            }
        }

        private bool EsUsuarioConPermisos(SPWeb web)
        {
            bool retVal = false;
            try
            {
                foreach (SPRoleAssignment r in web.RoleAssignments)
                {
                    SPGroup g = (SPGroup)r.Member;
                    foreach (SPUser u2 in g.Users)
                    {
                        if (u2.LoginName == UsuarioActual.LoginName)
                        {
                            return true;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                retVal = false;
            }
            return retVal;

        }

        private bool EstaAquestSiteExclos(SPWeb web, string[] SitesExc)
        {
            bool retVal = false;
            try
            {
                
                    foreach (string s in SitesExc)
                    {
                        if ((s.Trim().ToLower() == web.Name.ToLower()) || (s.Trim().ToLower() == web.Title.ToLower()))
                        {
                            return true;
                        }
                    }
                
            }
            catch (Exception ex)
            {
                retVal = false;
            }
            return retVal;

        }
    }
}
